﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using Miko.CS.Net;

namespace Socket_Client
{
    public partial class Form_Client : Form
    {
        public Client Client;
        public int markedID { get; private set; }
        public delegate void Act();
        List<MessageRecord> listRecord;
        string user = Dns.GetHostName();
        public object SelfLockObject;
        public Form fileForm;

        const int posListHeigth = 70;
        const int posImageSize = 64;
        const int posSpace = 3;
        const int posTextHeigth = 28;
        const int posStatePointY = 43;
        const int posStateSize = 15;
        const int posInfoHeigth = 33;
        const int mainImageSize = 128;
        const int minWidth = 100;
        const string FontName = "Microsoft YaHei";

        StringFormat format;
        StringFormat formatText;

        public Form_Client()
        {
            InitializeComponent();
            Client = new Client();
            Client.IDSet += Client_IDSet;
            Client.BroadcastStart += Client_BroadcastStart;
            Client.BroadcastFinsh += Client_BroadcastFinsh;
            Client.MessageReceived += Client_MessageReceived;
            Client.ClientShutdown += Client_ClientShutdown;
            
            listRecord = new List<MessageRecord>();
            SelfLockObject = new object();
        }

        private void Form_Client_Load(object sender, EventArgs e)
        {
            string name = Dns.GetHostName();
            tbUserName.Text = name;
            btnDisCon.Enabled = false;
            btnSend.Enabled = false;
            tbSendMsg.Focus();
            
            user = tbUserName.Text;
            
        }

        private void btnCon_Click(object sender, EventArgs e)
        {
            Client.Info.Name = tbUserName.Text;
            IPAddress ipAddr;
            int port;

            try
            {
                ipAddr = IPAddress.Parse(tbServerIP.Text);
                port = int.Parse(tbServerPort.Text);
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "错误!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            try
            {
                Client.Start(new IPEndPoint(ipAddr, port));
                btnCon.Enabled = false;
                btnDisCon.Enabled = true;
                btnSend.Enabled = true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "警告!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
        }

        private void btnDisCon_Click(object sender, EventArgs e)
        {
            if (Client.Running)
            {
                string message = "程序似乎已经连接至服务器, 确定要断开并重置么?";
                if (MessageBox.Show(this, message, "", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.No)
                {
                    return;
                }
            }
            Client.Stop();
            lbStatus.Text = "已断开";
            btnCon.Enabled = true;
            btnDisCon.Enabled = false;
            btnSend.Enabled = false;
        }

        private void Client_BroadcastStart(object sender, BroadcastStartEventArgs e)
        {
            bool flag = false;
            for (int i = 0; i < e.IDs.Length; i++)
            {
                if (markedID == e.IDs[i])
                {
                    flag = true;
                    break;
                }
            }
            if (!flag)
            {
                markedID = Client.Info.ID;
            }
        }

        private void Client_IDSet(object sender, EventArgs e)
        {
            markedID = Client.Info.ID;
            Invoke(new Act(() => Text = "客户端 ID: " + Client.Info.ID));
            Client.Send(0, MessageType.ClientInfo, Client.Info.ToStream());
        }

        private void Client_ClientShutdown(object sender, EventArgs e)
        {
            Invoke(new Act(() => Text = "未连接"));
        }

        private void Client_BroadcastFinsh(object sender, EventArgs e)
        {
            drawClientList();
        }

        private void Client_MessageReceived(object sender, MessageReceivedEventArgs e)
        {
            MessageRecord record = new MessageRecord(e.ClientID, MessageRecordType.Received, e.Message);
            lock (listRecord)
            {
                listRecord.Add(record);
            }
            messageRecordUpdate();
        }

        void drawClientList(int selecID = 0, bool mark = false)
        {
            ClientInfo[] info;

            lock (Client.ListClient)
            {

                foreach (ClientInfo n in Client.ListClient)
                {
                    if (n.Name == user)
                    {
                        n.Name = "我";
                    }
                }
                info = new ClientInfo[Client.ListClient.Count];
                Client.ListClient.CopyTo(info);
                
            }

            if (info.Length <= 0)
            {
                Invoke(new Act(() =>
                {
                    pictureBox1.Image = null;
                    pictureBox1.Size = new Size(0, 0);
                }));
                return;
            }

            // 鼠标点击后 标记出那个客户端
            if (mark)
            {
                if (selecID < info.Length)
                {
                    markedID = info[selecID].ID;
                }
            }

            int width = (panel1.Width - 2 > minWidth) ? panel1.Width - 2 : minWidth;
            int height = posListHeigth * info.Length;
            if (height > panel1.Height - 2)
            {
                width -= SystemInformation.VerticalScrollBarWidth;
            }
            Bitmap bitmap = new Bitmap(width, height);
            Graphics g = Graphics.FromImage(bitmap);

            Bitmap image = new Bitmap(mainImageSize, mainImageSize);
            Graphics gra = Graphics.FromImage(image);

            g.Clear(Color.White);

            for (int i = 0; i < info.Length; i++)
            {
                int x = 0;
                int y = i * posListHeigth;

                int pointTextX = posImageSize + posSpace * 2;
                int pointInfoX = pointTextX + posStateSize + posSpace;
                int pointInfoY = posTextHeigth + posSpace + 2;
                int widthText = width - posImageSize - posSpace * 3 - 1;
                int widthInfo = width - posImageSize - posStateSize - posSpace * 4 - 1;

                Rectangle rect = new Rectangle(x + 1, y + 1, width - 3, posListHeigth - 3);
                Rectangle rectText = new Rectangle(x + pointTextX, y + posSpace, widthText, posTextHeigth);
                Rectangle rectState = new Rectangle(x + pointTextX, y + posStatePointY, posStateSize, posStateSize);
                Rectangle rectBitmap = new Rectangle(x + posSpace, y + posSpace, posImageSize, posImageSize);
                Rectangle rectInfo = new Rectangle(x + pointInfoX, y + pointInfoY, widthInfo, posInfoHeigth);
                Rectangle rectImage = new Rectangle(0, 0, mainImageSize, mainImageSize);

                if (info[i].Image != null)
                {
                    g.DrawImage(info[i].Image, rectBitmap);
                    if (info[i].ID == markedID)
                    {
                        gra.DrawImage(info[i].Image, rectImage);
                    }
                }
                else
                {
                    byte[] color = BitConverter.GetBytes(info[i].ID);
                    Brush brush = new SolidBrush(Color.FromArgb(255, color[2], color[1], color[0]));

                    g.FillRectangle(brush, rectBitmap);
                    if (info[i].ID == markedID)
                    {
                        gra.FillRectangle(brush, rectImage);
                    }

                    if (info[i].Name.Length > 0)
                    {
                        char[] c = new char[1];
                        c[0] = info[i].Name[0];

                        g.DrawString(new string(c), new Font(FontName, 32), Brushes.White, rectBitmap, format);

                        if (info[i].ID == markedID)
                        {
                            gra.FillRectangle(brush, rectImage);
                            gra.DrawString(new string(c), new Font(FontName, 72), Brushes.White, rectImage, format);
                        }
                    }
                }

                g.DrawString(info[i].Name, new Font(FontName, 16), Brushes.Black, rectText, formatText);
                g.DrawString(info[i].Info, new Font(FontName, 9), Brushes.Gray, rectInfo, formatText);
                g.FillRectangle(new SolidBrush(Miko.CS.Net.Convert.StateToColor(info[i].State)), rectState);

                if (info[i].ID == markedID)
                {
                    g.FillRectangle(new SolidBrush(Color.FromArgb(64, Color.LightBlue)), rect);
                    g.DrawRectangle(Pens.LightBlue, rect);

                    Invoke(new Act(() =>
                    {
                        //label1.Text = info[i].Name;
                        //label2.Text = info[i].Info;
                        //label3.Text = info[i].ID.ToString();
                        lbStatus.Text = Miko.CS.Net.Convert.StateToString(info[i].State);

                        //pictureBox2.Image = image;我的大头像
                    }));
                }
            }

            Invoke(new Act(() =>
            {
                pictureBox1.Image = bitmap;
                pictureBox1.Size = bitmap.Size;

                btnChangeInfo.Visible = (Client.Info.ID == markedID);
            }));
        }

        void messageRecordUpdate()
        {
            StringBuilder sb = new StringBuilder();
            lock (listRecord)
            {
                listRecord.ForEach((r) =>
                {
                    if (r.TargetID != markedID)
                    {
                        return;
                    }

                    if (r.RecordType == MessageRecordType.Received)
                    {
                        sb.Append(r.Time + " 对方:\r\n" + r.Message + "\r\n");
                    }
                    if (r.RecordType == MessageRecordType.Send)
                    {
                        sb.Append(r.Time + " 本机:\r\n" + r.Message + "\r\n");
                    }
                });
            }

            Invoke(new Act(() =>
            {
                tbMsgList.Text = sb.ToString();
                tbMsgList.Select(tbMsgList.TextLength, 0);
                tbMsgList.ScrollToCaret();
            }));
        }

        void messageSend(string message)
        {
            Client.Send(markedID, message);
            tbSendMsg.Text = string.Empty;

            MessageRecord record = new MessageRecord(markedID, MessageRecordType.Send, message);
            lock (listRecord)
            {
                listRecord.Add(record);
            }
            messageRecordUpdate();
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            string message = tbSendMsg.Text + "\r\n";
            messageSend(message);
        }

        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            int t = e.Y / posListHeigth;
            drawClientList(t, true);
            messageRecordUpdate();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Client.Stop();
        }

        private void btnSendFile_Click(object sender, EventArgs e)
        {
            lock (SelfLockObject)
            {
                if (fileForm != null)
                {
                    return;
                }
                else
                {
                    fileForm = new Form_SendFile();
                    fileForm.Show(this);
                }
            }
        }

       
    }
}
